#include<stdio.h>
#include<pthread.h>
#include<gmp.h>
#include<time.h>

#define PRECISAO 33219280 //Precisão utilizada para o calculo de pi

pthread_mutex_t mutex_func = PTHREAD_MUTEX_INITIALIZER;

//Variaveis globais usadas para auxiliar o calculo de pi
mpf_t a0, a0_next, a1, a1_next, b0, b1, b1_next, t0, t1, p0, p0_next, p1, pi, pi_aux, pi_old;

int i = 0; //Variavel que conta as iterações

//Função que calcula as variaveis an, bn e pn
void *calcula_a_b_p(void *arg){
	mpf_add(a1,a0,b0);
	mpf_div_ui(a1,a1,2);

    mpf_mul(b1,a0,b0);
	mpf_sqrt(b1,b1);

    mpf_mul_ui(p1,p0,2);

	pthread_mutex_lock(&mutex_func);

	mpf_set(a0_next,a0);
	mpf_set(a0,a1);
	mpf_set(a1_next,a1);
	mpf_set(b0,b1);
	mpf_set(b1_next,b1);
	mpf_set(p0_next,p0);
	mpf_set(p0,p1);

	pthread_mutex_unlock(&mutex_func);
}

//Função que calcula a variavel yn
void *calcula_t(void *arg){
	pthread_mutex_lock(&mutex_func);

	mpf_sub(t1,a0_next,a1_next);
	mpf_pow_ui(t1,t1,2);
	mpf_mul(t1,p0_next,t1);
	mpf_sub(t1,t0,t1);

	pthread_mutex_unlock(&mutex_func);

	mpf_set(t0,t1);
}

int main(void){
	time_t start, end;
    	pthread_t thread[2];

	time(&start);

	mpf_set_default_prec(PRECISAO);

	//Inicialização das variáveis
	mpf_inits(a0,a0_next,a1,a1_next,b0,b1,b1_next,t0,t1,p0,p0_next,p1,pi,pi_aux,pi_old,NULL);

	//Pi "old" é 0, pi é 1 para que a comparação seja diferente na primeira vez
	mpf_set_d(pi_old,0);
	mpf_set_d(pi,1);

	mpf_set_d(a0,1);//a0 = 1.0

	mpf_set_d(b0,2);//b0 = 1.0/sqrt(2);
	mpf_sqrt(b0,b0);
	mpf_ui_div(b0,1,b0);

   	mpf_set_d(t0,1);//t0 = 1.0/4;
	mpf_div_ui(t0,t0,4);

   	mpf_set_d(p0,1);//p0 = 1.0;

	pthread_create(&thread[0], NULL,  calcula_a_b_p, NULL);
	pthread_join(thread[0], NULL);

	while(mpf_cmp(pi_old,pi) != 0){
		mpf_set(pi_old,pi);//pi_old agora é igual ao pi da iteração anterior

		pthread_create(&thread[0], NULL, calcula_a_b_p, NULL);
		pthread_create(&thread[1], NULL, calcula_t, NULL);
		pthread_join(thread[0], NULL);
		pthread_join(thread[1], NULL);

		mpf_add(pi,a1_next,b1_next);
		mpf_pow_ui(pi,pi,2);
		mpf_mul_ui(pi_aux,t1,4);
		mpf_div(pi,pi,pi_aux);
		gmp_printf("%da interacao: pi %.Ff\n\n",i+1, pi);//imprime qual o valor de pi na iteração i
		i++;
	}

	time(&end);
	printf("Numero de iterações necessárias: %d\n", i);
	printf("Tempo total: %lf segundos\n\n", difftime(end,start));

	mpf_clears(a0,a0_next,a1,a1_next,b0,b1,b1_next,t0,t1,p0,p0_next,p1,pi,pi_aux,pi_old,NULL);

	return 0;
}
